package whu.cachhe.makeorder.ui;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.location.Location;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MyLocationStyle;
import com.bumptech.glide.Glide;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import whu.cachhe.makeorder.R;
import whu.cachhe.makeorder.domain.Parking;
import whu.cachhe.makeorder.net.HttpRequest;
import whu.cachhe.makeorder.net.URLConstant;
import whu.cachhe.makeorder.util.BitmapUtil;
import whu.cachhe.makeorder.util.Logger;
import whu.cachhe.makeorder.view.LoadMoreListView;

/**
 * Created by CocoAdapter on 2018/3/20.
 */

public class ReservationsActivity extends AppCompatActivity {
    private MapView mapView;
    private PopupWindow popupWindow;
    private LinearLayout llBottom;
    private EditText etSearch;
    private ImageView imgClearSearch;

    private AMap aMap;
    private MyLocationStyle myLocationStyle;

    private ParkingAdapter parkingAdapter;
    private List<Parking> parkingList;

    private String queryText;
    private int sortBy = 1;
    private int pageSize = 10;
    private int pageIndex = 0;

    private boolean isFirstLocate = true;
    private double longitude;
    private double latitude;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reservations);

        init(savedInstanceState);
    }

    private void init(Bundle savedInstanceState) {
        initMapView(savedInstanceState);

        initSearchView();

        initPopupWindow();
    }

    private void initSearchView(){
        etSearch = findViewById(R.id.et_search);
        imgClearSearch = findViewById(R.id.img_clear);

        etSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH){
//                    TODO 这里需要判断是否为空，数据的清空与否，业务逻辑不是很正确
                    String query = v.getText().toString();
                    Logger.e(query);

                    hideSoftInputFromCallerView(v);
                    try {
                        getParkingsByParams(query, true);
                        return true;
                    } catch (JSONException e){
                        e.printStackTrace();
                    }
                }
                return false;
            }
        });
        etSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (TextUtils.isEmpty(s.toString()))
                    imgClearSearch.setEnabled(false);
                else
                    imgClearSearch.setEnabled(true);
            }
        });

        imgClearSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                etSearch.setText(null);
                hideSoftInputFromCallerView(etSearch);

                if (popupWindow.isShowing())
                    popupWindow.dismiss();

                parkingList.clear();
                parkingAdapter.notifyDataSetChanged();
                refreshMarker(aMap, parkingList);
                llBottom.setVisibility(View.GONE);
            }
        });
    }

    private void hideSoftInputFromCallerView(View v){
        v.clearFocus();

        InputMethodManager inputMethodManager = (InputMethodManager) v.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
        if (inputMethodManager != null && inputMethodManager.isActive())
            inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
    }

    private void initPopupWindow(){
        // 一个钩子用于重新弹出popupWindow
        llBottom = findViewById(R.id.ll_bottom);
        llBottom.setClickable(true);
        llBottom.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showPopupWindow();
            }
        });

        popupWindow = new PopupWindow(ReservationsActivity.this);
        // 长宽设定
        DisplayMetrics outMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
        popupWindow.setWidth(outMetrics.widthPixels);
        popupWindow.setHeight((int) (outMetrics.heightPixels * 0.666666));

        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        popupWindow.setFocusable(true);
        popupWindow.setOutsideTouchable(true);
        popupWindow.setTouchable(true);
        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                llBottom.setVisibility(View.VISIBLE);
            }
        });
        popupWindow.setAnimationStyle(R.style.animTranslate);

        View contentView = LayoutInflater.from(ReservationsActivity.this).inflate(R.layout.popup_reservations, null, false);
        popupWindow.setContentView(contentView);

        final LoadMoreListView listView = contentView.findViewById(R.id.list_view);
        if (parkingList == null)
            parkingList = new ArrayList<>();
        parkingAdapter = new ParkingAdapter(ReservationsActivity.this, parkingList);
        listView.setCapacity(pageSize);
        listView.setAdapter(parkingAdapter);
        listView.setOnLoadMoreListener(new LoadMoreListView.OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                try {
                    loadMore(listView);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                popupWindow.dismiss();
//                llBottom.setVisibility(View.INVISIBLE);

                Intent intent = new Intent(ReservationsActivity.this, ParkingActivity.class);
                intent.putExtra("parking", (Parcelable) parkingList.get(position));
                startActivity(intent);
            }
        });
    }

    private void showPopupWindow(){
        hideSoftInputFromCallerView(etSearch);
        if (popupWindow != null && !popupWindow.isShowing()){
            popupWindow.showAtLocation(findViewById(R.id.parent), Gravity.BOTTOM, 0, 0);
        }
    }

    private void initMapView(Bundle savedInstanceState) {
        //获取地图控件引用
        mapView = findViewById(R.id.map_view);
        //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState)，创建地图
        mapView.onCreate(savedInstanceState);
        if (aMap == null){
            aMap = mapView.getMap();
            aMap.showIndoorMap(true); // 开启室内地图

            myLocationStyle = new MyLocationStyle();
            myLocationStyle.interval(2000);
            aMap.setMyLocationStyle(myLocationStyle);
            aMap.setMyLocationEnabled(true);
            aMap.setOnMyLocationChangeListener(new AMap.OnMyLocationChangeListener() {
                @Override
                public void onMyLocationChange(Location location) {
                    longitude = location.getLongitude();
                    latitude = location.getLatitude();
                    // 在拿到定位数据后再发起一次 请求
                    if (isFirstLocate){
                        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);
                        aMap.setMyLocationStyle(myLocationStyle);
                        try {
                            getParkingsByParams(null, true);
                        } catch (JSONException e){
                            e.printStackTrace();
                        } finally {
                            isFirstLocate = false;
                        }
                    }
                }
            });
            aMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
                @Override
                public boolean onMarkerClick(Marker marker) {
                    Object object = marker.getObject();
                    if (object != null && object instanceof Parking){
                        Parking parking = (Parking) object;
                        Intent intent = new Intent(ReservationsActivity.this, ParkingActivity.class);
                        intent.putExtra("parking", (Parcelable) parking);
                        startActivity(intent);
                        return true;
                    }
                    return false;
                }
            });
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy(); //在activity执行onDestroy时执行mMapView.onDestroy()，销毁地图
    }

    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();  //在activity执行onResume时执行mMapView.onResume ()，重新绘制加载地图
    }

    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause(); //在activity执行onPause时执行mMapView.onPause ()，暂停地图的绘制
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);  //在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState)，保存地图当前的状态
    }

    /**
     * 根据parkingList刷新Map上的marker显示
     * @param aMap aMap
     * @param parkingList parkingList
     */
    private void refreshMarker(AMap aMap, List<Parking> parkingList){
        if (aMap == null)
            return;

        aMap.clear();
        if (parkingList == null)
            return;

        List<LatLng> latLngs = new ArrayList<>();
        for (int i = 0; i < parkingList.size(); i++){
            Parking parking = parkingList.get(i);

            LatLng latLng = new LatLng(parking.getLatitude(), parking.getLongitude());
            View markerView = LayoutInflater.from(ReservationsActivity.this).inflate(R.layout.view_marker, null);
            TextView tv = markerView.findViewById(R.id.tv_num);
            tv.setText((i + 1) + "");
            Marker marker = aMap.addMarker(new MarkerOptions()
                    .icon(BitmapDescriptorFactory.fromBitmap(BitmapUtil.convertViewToBitmap(markerView)))
                    .position(latLng));
            marker.setObject(parking);

            latLngs.add(latLng);
        }

        LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
        for (int i = 0; i < latLngs.size(); i++){
            boundsBuilder.include(latLngs.get(i));
        }

        aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 100));
    }

    /**
     * SearchText 里发起的查询
     * @param query 查询字串
     * @throws JSONException
     */
    private void getParkingsByParams(String query, final boolean showPopupWindow) throws JSONException{
        if (parkingList == null)
            parkingList = new ArrayList<>();

        queryText = query;

        JSONObject fparam = new JSONObject();
        fparam.put("uid", MainActivity.user.getReserveSysId())
                .put("query", query)
                .put("longitude", longitude)
                .put("latitude", latitude)
                .put("sortBy", sortBy)
                .put("pageSize", pageSize)
                .put("pageIndex", pageIndex);
        HttpRequest.post(URLConstant.HOST, "getParkingsByParams", fparam, new HttpRequest.HttpRequestCallback() {
            @Override
            public void onSuccess(final JSONObject response) {
                if (response.optInt("success") == 1){
                    parkingList.clear();

                    JSONArray parkings = response.optJSONObject("result").optJSONArray("data");
                    if (parkings != null && parkings.length() != 0){
                        int length = parkings.length();
                        for (int i = 0; i < length; i++){
                            JSONObject jParking = parkings.optJSONObject(i);
                            Parking parking = new Parking();
                            parking.setPid(jParking.optString("pid"));
                            parking.setName(jParking.optString("name"));
                            JSONArray jImgURLs = jParking.optJSONArray("imgURL");
                            List<String> imgURLs = new ArrayList<>();
                            for (int j = 0; j < jImgURLs.length(); j++){
                                imgURLs.add(jImgURLs.optString(j));
                            }
                            parking.setImgURLs(imgURLs);
                            parking.setLotSize(jParking.optInt("lotSize"));
                            parking.setLocation(jParking.optString("location"));
                            parking.setDistance(jParking.optString("distance"));
                            parking.setDistanceUnit(jParking.optString("dis_unit"));
                            parking.setLongitude(jParking.optDouble("longitude"));
                            parking.setLatitude(jParking.optDouble("latitude"));

                            parkingList.add(parking);
                        }
                    } else {
                        llBottom.setVisibility(View.GONE);
                    }

                    parkingAdapter.notifyDataSetChanged();
                    refreshMarker(aMap, parkingList);
                    if (showPopupWindow)
                        showPopupWindow();
                } else {
                    String error = response.optString("result");
                    if (error != null && !error.equals("null"))
                        Toast.makeText(ReservationsActivity.this, error, Toast.LENGTH_LONG).show();

                    if (parkingList != null)
                        parkingList.clear();

                    refreshMarker(aMap, parkingList);
                    llBottom.setVisibility(View.GONE);
                    parkingAdapter.notifyDataSetChanged();
                }
            }

            @Override
            public void onFailure() {
                Toast.makeText(ReservationsActivity.this, "网络异常", Toast.LENGTH_LONG).show();
            }
        });
    }

    /**
     * PopupWindow 里发起的上拉加载
     * [TODO] Class not found when unmarshalling, 当数据量很大的时候，程序会报错, 详细原因见 https://blog.csdn.net/candyguy242/article/details/53929327
     * @param loadMoreListView LoadMoreListViews
     * @throws JSONException
     */
    private void loadMore(final LoadMoreListView loadMoreListView) throws JSONException {
        JSONObject fparam = new JSONObject();
        fparam.put("uid", MainActivity.user.getReserveSysId())
                .put("query", queryText)
                .put("longitude", longitude)
                .put("latitude", latitude)
                .put("sortBy", sortBy)
                .put("pageSize", pageSize)
                .put("pageIndex", pageIndex + 1);

        HttpRequest.post(URLConstant.HOST, "getParkingsByParams", fparam, new HttpRequest.HttpRequestCallback() {
            @Override
            public void onSuccess(JSONObject response) {
                if (response.optInt("success") == 1){
                    JSONArray parkings = response.optJSONObject("result").optJSONArray("data");
                    for (int i = 0; i < parkings.length(); i++){
                        JSONObject jParking = parkings.optJSONObject(i);
                        Parking parking = new Parking();
                        parking.setPid(jParking.optString("pid"));
                        parking.setName(jParking.optString("name"));
                        JSONArray jImgURLs = jParking.optJSONArray("imgURL");
                        List<String> imgURLs = new ArrayList<>();
                        for (int j = 0; j < jImgURLs.length(); j++){
                            imgURLs.add(jImgURLs.optString(j));
                        }
                        parking.setImgURLs(imgURLs);
                        parking.setLotSize(jParking.optInt("lotSize"));
                        parking.setLocation(jParking.optString("location"));
                        parking.setDistance(jParking.optString("distance"));
                        parking.setDistanceUnit(jParking.optString("dis_unit"));
                        parking.setLongitude(jParking.optDouble("longitude"));
                        parking.setLatitude(jParking.optDouble("latitude"));

                        parkingList.add(parking);
                    }

                    pageIndex++;

                    loadMoreListView.finishLoading();
                    ((BaseAdapter)loadMoreListView.getBindAdapter()).notifyDataSetChanged();
                } else {
                    loadMoreListView.finishLoading();
                    ((BaseAdapter)(loadMoreListView.getBindAdapter())).notifyDataSetChanged();
                    String error = response.optString("result");
                    if (error != null && !error.equals("null"))
                        Toast.makeText(ReservationsActivity.this, error, Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onFailure() {
                loadMoreListView.finishLoading();
                Toast.makeText(ReservationsActivity.this, "网络异常", Toast.LENGTH_LONG).show();
            }
        });
    }

    private static class ParkingAdapter extends BaseAdapter {
        private List<Parking> parkingList;
        private Context context;

        public ParkingAdapter(Context context, List<Parking> parkingList){
            this.context = context;
            this.parkingList = parkingList;
        }

        @Override
        public int getCount() {
            return parkingList.size();
        }

        @Override
        public Object getItem(int position) {
            return parkingList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null){
                convertView = LayoutInflater.from(context).inflate(R.layout.item_parking, null);
                holder = new ViewHolder();
                holder.imageView = convertView.findViewById(R.id.img_view);
                holder.index = convertView.findViewById(R.id.tv_index);
                holder.name = convertView.findViewById(R.id.tv_name);
                holder.lotCount = convertView.findViewById(R.id.tv_lot_count);
                holder.location = convertView.findViewById(R.id.tv_location);
                holder.distance = convertView.findViewById(R.id.tv_distance);

                convertView.setTag(holder);
            } else
                holder = (ViewHolder) convertView.getTag();
            // update holder
            Parking parking = parkingList.get(position);
            holder.index.setText((position + 1) + "");
            holder.name.setText(parking.getName());
            holder.lotCount.setText(parking.getLotSize() + "");
            holder.location.setText(parking.getLocation());
            holder.distance.setText(parking.getDistance() + parking.getDistanceUnit());
            Glide.with(context)
                    .load(parking.getImgURL())
                    .placeholder(R.mipmap.defalut)
                    .error(R.mipmap.defalut)
                    .into(holder.imageView);

            return convertView;
        }
    }

    private static class ViewHolder{
        ImageView imageView;
        TextView index, name, lotCount, location, distance;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            this.finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}
